# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import os
import re
import subprocess
import time

from signal import SIGTERM


_DEFAULT_PORT = 8080


conf = """
ServerName localhost
DocumentRoot %(HOME)s/home
Listen %(port)d

PidFile  %(HOME)s/pid

LogFormat %(log)s    common
LogLevel   warn
ErrorLog   %(HOME)s/error_log
CustomLog  %(HOME)s/access_log common

<Directory />
    # Don't look for .htaccess files.
    AllowOverride none
</Directory>

<Location />
    DAV svn
    SVNParentPath %(HOME)s
    AuthType Basic
    AuthName 'test'
    AuthUserFile %(HOME)s/passwd
    Require valid-user
</Location>
"""

# password 'rayjandom'
passwd = """unittest:xCGl35kV9oWCY
basil:xCGl35kV9oWCY
jrandom:xCGl35kV9oWCY
jconstant:xCGl35kV9oWCY
"""


def GetPort():
  return int(os.getenv('SVN_PORT', _DEFAULT_PORT))


class Httpd(object):
  def __init__(self, home, httpd=None):
    self.home = home
    if httpd is None:
      self.httpd = 'httpd'
    else:
      self.httpd = httpd
    self.port = GetPort()
    self._builtin_modules = self._libexecdir = None

  def _GetBuiltinModules(self):
    if self._builtin_modules is None:
      s = subprocess.Popen([self.httpd, '-l'],
                           stdout=subprocess.PIPE).communicate()[0]
      self._builtin_modules = s
    return self._builtin_modules
  builtin_modules = property(_GetBuiltinModules)

  def _GetLibexecdir(self):
    if self._libexecdir is None:
      # TODO(epg): Find apxs better.
      apxs = re.sub('httpd$', 'apxs', self.httpd)
      s = subprocess.Popen([apxs, '-q', 'LIBEXECDIR'],
                           stdout=subprocess.PIPE).communicate()[0]
      self._libexecdir = s.rstrip(os.linesep)
    return self._libexecdir
  libexecdir = property(_GetLibexecdir)

  def MaybeLoadModule(self, mod, fp):
    if 'mod_' + mod not in self.builtin_modules:
      fp.write('LoadModule %s_module "%s/mod_%s.so"\n'
               % (mod, self.libexecdir, mod))

  def start(self):
    open(self.home + '/passwd', 'w').write(passwd)

    os.mkdir(self.home + '/home/.subversion')
    fp = open(self.home + '/home/.subversion/servers', 'a')
    fp.write('[groups]\n'
             'all=*\n'
             '[all]\n'
             'store-plaintext-passwords = yes\n'
             'http-library = %s\n' % (os.environ.get('HTTP_LIBRARY', 'neon'),))
    fp.close()

    fn = self.home + '/httpd.conf'
    fp = open(fn, 'w')
    fp.write(conf % {
      'HOME':     self.home,
      'log':      '"%h %u %t %r %>s %B %D %X %{User-Agent}i"',
      'port':     self.port,
    })
    for mod in ['auth_basic', 'authn_file', 'authz_user', 'dav', 'log_config',
                # We know these two svn modules aren't built-in but
                # it's easier to treat them the same.
                'dav_svn', 'authz_svn']:
      self.MaybeLoadModule(mod, fp)
    fp.close()

    self.pid = os.fork()
    if self.pid == 0:
      os.setpgrp()
      os.execlp(self.httpd, self.httpd, '-f', fn, '-DFOREGROUND')

    # Give httpd a second to load up.
    time.sleep(1)

  def stop(self):
    # Avoid runtest tmpdir cleanup finding the pid file but httpd has
    # removed it by the time runtest goes to remove it.  Wish we could
    # stop it from writing the pidfile in the first place...
    os.unlink(self.home + '/pid')
    os.kill(self.pid, SIGTERM)

if __name__ == '__main__':
  import sys, tempfile
  try:
    dirname = sys.argv[1]
  except IndexError:
    dirname = tempfile.mkdtemp()
  h = Httpd(dirname)
  h.start()
  print 'repositories under', dirname, '(file://' + dirname + ')'
  print 'kill', h.pid, 'to stop'
